#coding:utf8
import os,sys,subprocess,json,types,time
from CollectSpider.service.task import  Task,init_engine,every_day,update_taskstatus_by_id
from exceptions import Exception
from CollectSpider.kancloud import db
from time import sleep
from CollectSpider.globalvar.globalvar import task_list,subprocess_list,time_list
from CollectSpider.kancloud.MsgSend import MsgSend
from CollectSpider.kancloud.FileUtil import FileUtil,replaceCharEntity,is_None
from CollectSpider.kancloud.PrintMsg import print_msg,unicode_to_str
from CollectSpider.kancloud.Ping import is_ping
#获取脚本文件的当前路径
def cur_file_dir():
    #获取脚本路径
    path = sys.path[0]
    #判断为脚本文件还是py2exe编译后的文件，如果是脚本文件，则返回的是脚本的目录，如果是py2exe编译后的文件，则返回的是编译后的文件路径
    if os.path.isdir(path):
        return path
    elif os.path.isfile(path):
        return os.path.dirname(path)
#获取任务 
def get_task():
    task=Task()
    return task.getAll()

#问答，新闻的规则应用通过任务
def make_spder_by_rule(task):
    taskutil=Task()
    fileutil=FileUtil("spiders")
    result_msg=None
    if task is not None:
        #1 为问答
        if int(task["task_type"])==1:
            content=task["rule_match"] 
            filename="spider_"+str(task["id"])+".py".strip()
            #MD5比较
            compare_result=fileutil.compare_md5_content(filename, content)
            if content is not None:
                if compare_result!=True:
                    fileutil.write_to_file(filename,replaceCharEntity(content))
                    result_msg=fileutil.file_exists(filename)
                else:
                    result_msg="created"
            else:
                result_msg="error"
                print_msg("问答网站任务名:%s 没有爬虫规则,不能生产规则文件,任务编号:%s" % (unicode_to_str(task["task_name"]),unicode_to_str(task["id"])))
            
        #2为新闻
        elif int(task["task_type"]==2):
            search_engine_list=taskutil.get_search_engine_by_task(task)
            for engine in search_engine_list:
                content=engine["se_rule"]
                if content is not None:
                    filename="spider_"+str(task["id"])+"_"+str(engine["id"])+".py".strip()
                    compare_result=fileutil.compare_md5_content(filename, content)
                    if compare_result!=True:
                        fileutil.write_to_file(filename,replaceCharEntity(content))
                        result_msg=fileutil.file_exists(filename)
                    else:
                        result_msg="created"
                else:
                    result_msg="error"
                    print_msg("搜索引擎:%s 没有爬虫规则,不能生产规则文件,爬虫编号:%s" % (unicode_to_str((engine["se_name"])),unicode_to_str(engine["id"])))
            return result_msg 
            
    else:
        raise ValueError("参数错误,不能为空")

#检查数据库中的状态
def check_db_status():
    task=Task()
    temp_taskids=[]
    run_taskids=[]
    del_ids=[]
    insert_ids=[]
    del_list=[]
    insert_list=[]
    temp_tasklist=task.getAll()
    for temp_task in temp_tasklist:
        temp_taskids.append(temp_task["id"])

    for run_task in task_list:
        run_taskids.append(run_task["id"])
        
    for run_id in run_taskids:
        if run_id not in temp_taskids:
            del_ids.append(run_id)
    
    for temp_id in temp_taskids:
        if temp_id not in run_taskids:
            insert_ids.append(temp_id)
            
    for insert_id in insert_ids:
        temp_task=db.select("select * from spider_task where id=?",insert_id)
        insert_list.append(temp_task)
#     for delete_id in del_ids:
#         temp_task=db.select("select * from spider_task where id=?",delete_id)
#         del_list.append(temp_task)
    
    return {"insert":insert_list,"del":del_ids}
    
#更新循环体变量
def kill_subprc_by_task():
    #检查任务变化情况
    dictlist=check_db_status()
    del_ids=dictlist["del"]
    running_tasklist=[]
    for sub_task  in subprocess_list:
        running_tasklist.append(sub_task.keys()[0])
    
    if is_None(del_ids) is not None :
        #杀掉进程
        if is_None(subprocess_list) is not None:           
            for run_id in del_ids:
                subprc=get_subprocess_task(run_id)
                if subprc.returncode==None and subprc is not None:  
                    #杀掉子进程   
                    subprc.kill()
                    #删除该元素
                    index=subprocess_list.index(dict({run_id:subprc}))
                    del subprocess_list[index]
                    #修改状态
                    update_taskstatus_by_id(run_id)
    
   
def get_subprocess_task(task_id):
    sub_pro=None
    for subprc in subprocess_list:
        taskid=subprc.keys()[0]
        if taskid==task_id:
            sub_pro=subprc.get(taskid)
            break;
    return sub_pro

#根据调度的类型 来  运行爬虫
def run_way(task):
    if task is None and type(task)==types.DictType:
        raise ValueError("params error")
    else:
        #类型为2  定天运行
        if(int(task["schedule_type"])==2):
            every_day(task["id"])
            if is_None(time_list) is not None:
                #定天执行spider
                time_run=time_list[0]
                nowtime=int(time.time())
                #当前时间跟设定时间,的差值范围
                if time_run-nowtime>=0:
                    #添加启动时间
                    print_msg("任务id:%s,调度方式为 2 ,时间点:%s，开始执行 " % (unicode_to_str(task["id"]),time_run))
                    task["run_time"]=time_run
                    dispatch_spider(task)
                    #任务启动时间超过了当前时间,不予执行
                elif time_run-nowtime<0:
                    print_msg("任务id:%s,调度方式为 2 没有可以允许的时间点，时间超时,或执行过,请知晓" % unicode_to_str(task["id"]))
                else:
                    print_msg("任务id:%s ,执行时间还没到，不予执行" % unicode_to_str(task["id"]))
                    
                            #
            else:
                print_msg("任务id:%s,调度方式为 2 没有可以允许的时间点或时间点还没到,请知晓" % unicode_to_str(task["id"]))
            
        #类型为1  及时运行
        elif(int(task["schedule_type"])==1):
            #代表重复执行,的时间间隔，不标记 -1
            if int(task["time_interval"])>=0:                
                #代表执行单次，执行之后标记为 -1
                dispatch_spider(task)
            else:
                print_msg("任务id:%s 调度方式为1 单次运行， 并且任务 已经执行过，不予执行" % unicode_to_str(task["id"]))
                
def init_tasklist():
    tasklists=get_task()
    #循环外杀进程
    kill_subprc_by_task()
    del task_list[:]
    for task in tasklists:
        #
        task_list.append(task)

#添加参数，url_start,spider_name ,spier_urls    
def make_run_params(task):
    fileutil=FileUtil("spiders")
    tk=Task()
    if task is not None:
        if int(task["task_type"])==2:
            start_url=[]
            spider_names=[]
            spider_urls=[]
            search_engine_list=tk.get_search_engine_by_task(task)
            for engine in search_engine_list:
                filename="spider_"+str(task["id"])+"_"+str(engine["id"])+".py".strip()
                if fileutil.file_exists(filename): 
                    start_url.append(replaceCharEntity(engine["se_add"]))
                    spider_name=fileutil.get_spider_name(filename)
                    spider_names.append(spider_name)
                    if is_ping(replaceCharEntity(engine["se_add"])):
                        spider_urls.append({spider_name:replaceCharEntity(engine["se_add"])})
            task["url_start"]=start_url
            task["spider_names"]=spider_names
            task["spider_urls"]=spider_urls
            
        elif int(task["task_type"])==1:
            spider_name=None
            start_url=None
            spider_urls=[]
            filename="spider_"+str(task["id"])+".py".strip()
            if fileutil.file_exists(filename):
                start_url=replaceCharEntity(task["url_start"])
                spider_name=fileutil.get_spider_name(filename)
                if is_ping(replaceCharEntity(task["url_start"])):
                    spider_urls.append({spider_name:start_url})
                
            task["spider_names"]=spider_name
            task["url_start"]=start_url
            task["spider_urls"]=spider_urls
        return task
            
def check_task():
        #加入while循环，如果任务全部完成，就退出循环
        #初始化全局 的任务列表
        #运行中到任务清零
        init_tasklist()
        if is_None(task_list) is not None:
            for task in task_list:
                dictlist=check_db_status()
                del_ids=dictlist["del"]
                current_taskid=task["id"]
                if is_None(del_ids) is not None and current_taskid in del_ids:
                    print_msg("数据库中设定不执行，应跳过")
                    continue
                if int(task["page_count"])<=0:
                    print_msg("任务抓取数小于0，不合理，不予执行，应跳过")
                    continue
                else:
                    #生产爬虫文件
                    result_msg=make_spder_by_rule(task)
                    if result_msg=="error":
                        print_msg("规则不能为空，请定义规则,任务不予运行")
                        continue
                    elif result_msg==False:
                        print_msg("爬虫文件创建失败,清注意，任务不予运行")
                        continue
                    #添加运行参数
                    task=make_run_params(task)  
                    #开始调度
                    url=task["url_start"]
                    task_status=task["task_status"]

                    print_msg("开始检查开始路径：%s" % unicode_to_str(url))
                    if url is not None  and  task["spider_urls"]:
                        #传参到调度脚本
                        if task_status==2:
                            print_msg("合法路径,开始爬虫调度:%s" % unicode_to_str(url))
                            run_way(task) #根据任务类型 自动  使用相对应的调度方式
                        else:
                            print_msg("该任务正在执行" )  
                    else:
                        #发出警告，开始路径有误!
                        MsgSend.send_msg(**dict({"message":"任务id:"+str(task["id"])+" start_url 无效或 url 不能联通，造成没有可调度的爬虫，不予执行","code":401,"extra":"启动时路径检查错误"}))
                        print_msg("无效start_url: %s" % unicode_to_str(url))
                
                    #检查任务变化情况
                    #循环内杀进程,里外结合
                    kill_subprc_by_task()
        else:
            print_msg("没有可执行的任务!请知悉")
                        
#调度程序
def dispatch_spider(kwargs):
    try:
        #加载调度程序:
        dispatch=cur_file_dir()+os.sep+"dispatch_spider.py"
        #构造参数
        if kwargs is not None:
            params=json.dumps(dict(kwargs), ensure_ascii=False)
            child = subprocess.Popen(["python",dispatch,params])
            print_msg("spider load success: %s" % child.pid)
            #维护子进程对象列表
            subprocess_list.append({kwargs["id"]:child})
            print_msg("dispatch_spider exit, code: %s" % child.returncode)
        else:
            #发出警告,任务参数有误!
            print_msg("参数有误")
            
    except Exception,e:
        
        print_msg(e)
        
        
    
if __name__=='__main__':
    init_engine()
    while True:
        check_task()
        sleep(3)
    
